/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/*!
  \file			module.cc
  \date			Dec 2011
  \author		TNick

  \brief		Contains the implementation for Module class


*//*

 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Please read COPYING and README files in root folder
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

*/
/* ------------------------------------------------------------------------- */
/* ========================================================================= */
//
//
//
//
/*  INCLUDES    ------------------------------------------------------------ */


#include	<pgscript.h>
#include	<pgscript_internal.h>


#ifdef	USE_USERMSG
#include	<UMSG.h>
#endif

#include	<session.h>

#include	<uservar.h>
#include	<userfunc.h>

#include	<pgsave/ipgsave.h>


#include	"module.h"

/*  INCLUDES    ============================================================ */
//
//
//
//
/*  DEFINITIONS    --------------------------------------------------------- */

using namespace PgScr;

/*  DEFINITIONS    ========================================================= */
//
//
//
//
/*  DATA    ---------------------------------------------------------------- */


/*  DATA    ================================================================ */
//
//
//
//
/*  CLASS    --------------------------------------------------------------- */

/* ------------------------------------------------------------------------- */
Module::Module	( QString md_name )
{
	bld_in_var_cnt = 0;
	bld_in_var = NULL;
	bld_in_fun_cnt = 0;
	bld_in_fun = NULL;
	name_ = md_name;

	Q_ASSERT( Session::def_ss != NULL );
	prnt_ss = Session::def_ss;
	Session::def_ss->appendModule( this );

}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
Module::Module	( QString md_name, Session * parent_ss )
{
	bld_in_var_cnt = 0;
	bld_in_var = NULL;
	bld_in_fun_cnt = 0;
	bld_in_fun = NULL;
	name_ = md_name;

	if ( parent_ss == NULL )
	{
		Q_ASSERT( Session::def_ss != NULL );
		parent_ss = Session::def_ss;
	}
	prnt_ss = parent_ss;
	parent_ss->appendModule( this );

}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
Module::~Module	( void )
{
	Q_ASSERT( prnt_ss != NULL );
	if ( isCoreModule( this ) )
		remCoreModule( this );

	prnt_ss->removeModule( this );
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
Module*		Module::module			( Session * ss, int i )
{
	if ( ss == NULL )
	{
		Q_ASSERT( Session::def_ss != NULL );
		ss = Session::def_ss;
	}
	return ss->module( i );
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
Module*		Module::module			( int i )
{
	Q_ASSERT( Session::def_ss != NULL );
	return module( Session::def_ss, i );
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
int			Module::module			( Session * ss, Module * md )
{
	if ( ss == NULL )
	{
		Q_ASSERT( Session::def_ss != NULL );
		ss = Session::def_ss;
	}
	Q_ASSERT( ss != NULL );
	return ss->module( md );

}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
int			Module::module			( Module * md )
{
	Q_ASSERT( Session::def_ss != NULL );
	return module( Session::def_ss, md );
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
Module*		Module::module			( Session * ss, QString m_name )
{
	if ( ss == NULL )
	{
		Q_ASSERT( Session::def_ss != NULL );
		ss = Session::def_ss;
	}
	return ss->module( m_name );
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
Module*		Module::module			( QString m_name )
{
	Q_ASSERT( Session::def_ss != NULL );
	return module( Session::def_ss, m_name );
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
bool		Module::isCoreModule	( Module * md )
{
	Q_ASSERT( md->prnt_ss != NULL );
	return md->prnt_ss->isCoreModule( md );
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void		Module::addCoreModule	( Module * md )
{
	Q_ASSERT( md->prnt_ss != NULL );
	md->prnt_ss->addCoreModule( md );
}
/* ========================================================================= */


/* ------------------------------------------------------------------------- */
void		Module::remCoreModule	( Module * md )
{
	Q_ASSERT( md->prnt_ss != NULL );
	md->prnt_ss->remCoreModule( md );
}
/* ========================================================================= */


/* ------------------------------------------------------------------------- */
void		Module::save			( PgSave::IPgSave &targ_i )
{
	int	i;

	targ_i.setPath( name_ );

	/* predefined variables */
	targ_i.setPath( MOD_PVAR_GROUP );

	for ( i = 0; i < bld_in_var_cnt; i++ )
	{
		bld_in_var->save( targ_i );
	}

	targ_i.cdUp();
	/* predefined variables */


	/* user-defined variables */
	targ_i.setPath( MOD_UVAR_GROUP );

	for ( i = 0; i < usr_var_.count(); i++ )
	{
		usr_var_.at( i )->save( targ_i );
	}

	targ_i.cdUp();
	/* user-defined variables */

	targ_i.cdUp();

}
/* ========================================================================= */


/* ------------------------------------------------------------------------- */
Module *	Module::loadFull			(
		QString s_name, Session * targ_ses, PgSave::IPgSave &targ_i )
{
	Module *	ret_m;
	ret_m = new Module( s_name, targ_ses );
	ret_m->loadFull( targ_i );
	return ret_m;
}
/* ========================================================================= */


/* ------------------------------------------------------------------------- */
void	Module::load				( PgSave::IPgSave &targ_i )
{

}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void	Module::loadFull			( PgSave::IPgSave &targ_i )
{
	int					i;
	QString				s_name_loc;

	targ_i.setPath( name_ );

	/* predefined variables */
	targ_i.setPath( MOD_PVAR_GROUP );

	i = 0;
	while ( i < MAX_COMPONENTS_COUNT )
	{
		s_name_loc.setNum( i );
		if ( ! targ_i.exists( s_name_loc + "/" + VAR_NAME ))
			break;

		UserVar::load( s_name_loc, this, targ_i );

		i++;
	}

	targ_i.cdUp();
	/* predefined variables */


	/* user-defined variables */
	targ_i.setPath( MOD_UVAR_GROUP );

	i = 0;
	while ( i < MAX_COMPONENTS_COUNT )
	{
		s_name_loc.setNum( i );
		if ( ! targ_i.exists( s_name_loc + "/" + VAR_NAME ))
			break;

		UserVar::load( s_name_loc, this, targ_i );

		i++;
	}

	targ_i.cdUp();
	/* user-defined variables */



	targ_i.cdUp();
}
/* ========================================================================= */


///* ------------------------------------------------------------------------- */
//UserVar *			Module::findVariable			( const QString & var_n )
//{

//	return UserVar::findVariable( var_n, usr_var_, bld_in_var, bld_in_var_cnt );
//}
///* ========================================================================= */

///* ------------------------------------------------------------------------- */
//bool				Module::appendVar				( UserVar * var_inst )
//{
//	return UserVar::appendVar( var_inst, usr_var_, bld_in_var, bld_in_var_cnt );
//}
///* ========================================================================= */

///* ------------------------------------------------------------------------- */
//bool				Module::removeVar				( UserVar * var_inst )
//{
//	return UserVar::removeVar( var_inst, usr_var_ );
//}
///* ========================================================================= */

///* ------------------------------------------------------------------------- */
//bool				Module::removeVar				( const QString & s_name )
//{
//	return UserVar::removeVar( s_name, usr_var_ );
//}
///* ========================================================================= */

///* ------------------------------------------------------------------------- */
//UserFunc *			Module::findFunction			( const QString & fun_n )
//{
//	return UserFunc::findFunction( fun_n, usr_fun_, bld_in_fun, bld_in_fun_cnt );
//}
///* ========================================================================= */

///* ------------------------------------------------------------------------- */
//bool				Module::appendFun				( UserFunc * fun_inst )
//{
//	return UserFunc::appendFun( fun_inst, usr_fun_, bld_in_fun, bld_in_fun_cnt );
//}
///* ========================================================================= */

///* ------------------------------------------------------------------------- */
//bool				Module::removeFun				( UserFunc * fun_inst )
//{
//	return UserFunc::removeFun( fun_inst, usr_fun_ );
//}
///* ========================================================================= */

///* ------------------------------------------------------------------------- */
//bool				Module::removeFun				( const QString & s_name )
//{
//	return UserFunc::removeFun( s_name, usr_fun_ );
//}
///* ========================================================================= */


#ifdef	PGSCRIPT_TESTS
/* ------------------------------------------------------------------------- */
void				PgScr::Module_Tests					(
		int & performed, int & succeded )
{
	QString		Outcm;
	performed = 0;
	succeded = 0;



	if ( Module::module( 101 ) == NULL )	TEST_OK
			else	TEST_FAIL
			qDebug() << "Module integer search when empty..." << Outcm;
	performed++;

	if ( Module::module( (Module*) 0x101010 ) == -1 )	TEST_OK
			else	TEST_FAIL
			qDebug() << "Module pointer search when empty..." << Outcm;
	performed++;

	if ( Module::module( "some name") == NULL )	TEST_OK
			else	TEST_FAIL
			qDebug() << "Module string search when empty..." << Outcm;
	performed++;


	if ( Module::module(  Session::def_ss, 101 ) == NULL )	TEST_OK
			else	TEST_FAIL
			qDebug() << "Module integer search in session when empty..." << Outcm;
	performed++;

	if ( Module::module( Session::def_ss, (Module*) 0x101010 ) == -1 )	TEST_OK
			else	TEST_FAIL
			qDebug() << "Module pointer search in session when empty..." << Outcm;
	performed++;

	if ( Module::module( Session::def_ss, "some name") == NULL )	TEST_OK
			else	TEST_FAIL
			qDebug() << "Module string search in session when empty..." << Outcm;
	performed++;


	Module * ts_1 = new Module( QString() );

	if ( Module::module( 0 ) == ts_1 )	TEST_OK
			else	TEST_FAIL
			qDebug() << "Module integer search with one ..." << Outcm;
	performed++;

	if ( Module::module( ts_1 ) == 0 )	TEST_OK
			else	TEST_FAIL
			qDebug() << "Module pointer search with one..." << Outcm;
	performed++;

	if ( Module::module( QString() ) == ts_1 )	TEST_OK
			else	TEST_FAIL
			qDebug() << "Module string search with one..." << Outcm;
	performed++;


	if ( Module::module(  Session::def_ss, 0 ) == ts_1 )	TEST_OK
			else	TEST_FAIL
			qDebug() << "Module integer search in session with one..." << Outcm;
	performed++;

	if ( Module::module( Session::def_ss, ts_1 ) == 0 )	TEST_OK
			else	TEST_FAIL
			qDebug() << "Module pointer search in session with one..." << Outcm;
	performed++;

	if ( Module::module( Session::def_ss, QString() ) == ts_1 )	TEST_OK
			else	TEST_FAIL
			qDebug() << "Module string search in sessionwith one..." << Outcm;
	performed++;

	delete	ts_1;


	if ( Module::module( 101 ) == NULL )	TEST_OK
			else	TEST_FAIL
			qDebug() << "Module integer search after delete..." << Outcm;
	performed++;

	if ( Module::module( (Module*) 0x101010 ) == -1 )	TEST_OK
			else	TEST_FAIL
			qDebug() << "Module pointer search after delete..." << Outcm;
	performed++;

	if ( Module::module( "some name") == NULL )	TEST_OK
			else	TEST_FAIL
			qDebug() << "Module string search after delete..." << Outcm;
	performed++;


	if ( Module::module(  Session::def_ss, 101 ) == NULL )	TEST_OK
			else	TEST_FAIL
			qDebug() << "Module integer search in session after delete..." << Outcm;
	performed++;

	if ( Module::module( Session::def_ss, (Module*) 0x101010 ) == -1 )	TEST_OK
			else	TEST_FAIL
			qDebug() << "Module pointer search in session after delete..." << Outcm;
	performed++;

	if ( Module::module( Session::def_ss, "some name") == NULL )	TEST_OK
			else	TEST_FAIL
			qDebug() << "Module string search in session after delete..." << Outcm;
	performed++;



	ts_1 = new Module( QString(), Session::def_ss );
	ts_1->setName( "some name" );
	if ( Module::module( Session::def_ss, "some name") == ts_1 )	TEST_OK
			else	TEST_FAIL
			qDebug() << "Module name search in session ..." << Outcm;
	performed++;
	delete	ts_1;


	int test_sz = 1000;
	int i;
	bool b_ok =  true;
	qDebug() << "Now testing with a number of " << test_sz << " modules";
	Module ** mdl_l = (Module **)malloc( sizeof(Module *) * test_sz );
	Module ** mdl_itr = mdl_l;
	for ( i = 0; i < test_sz; i++ )
	{
		mdl_itr[i] = new Module( QString::number( i ) );
	}

	for ( i = 0; i < test_sz; i++ )
	{
		if ( mdl_itr[i]->name() != QString::number( i ) )
		{
			b_ok = false;
			break;
		}
	}
	if ( b_ok )	TEST_OK
			else	TEST_FAIL
			qDebug() << " - testing name()..." << Outcm;
	performed++; b_ok = true;



	for ( i = 0; i < test_sz; i++ )
	{
		if ( Module::module( QString::number( i ) ) != mdl_itr[i] )
		{
			b_ok = false;
			break;
		}
	}
	if ( b_ok )	TEST_OK
			else	TEST_FAIL
			qDebug() << " - testing module() with string..." << Outcm;
	performed++; b_ok = true;


	for ( i = 0; i < test_sz; i++ )
	{
		if ( Module::module( mdl_itr[i] ) != i )
		{
			b_ok = false;
			break;
		}
	}
	if ( b_ok )	TEST_OK
			else	TEST_FAIL
			qDebug() << " - testing module() with pointer..." << Outcm;
	performed++; b_ok = true;


	for ( i = 0; i < test_sz; i++ )
	{
		if ( Module::module( i ) != mdl_itr[i] )
		{
			b_ok = false;
			break;
		}
	}
	if ( b_ok )	TEST_OK
			else	TEST_FAIL
			qDebug() << " - testing module() with index..." << Outcm;
	performed++; b_ok = true;


	for ( i = 0; i < test_sz; i++ )
	{
		if ( ( i / 2 ) * 2 == i )
		{
			Module::addCoreModule( mdl_itr[i] );
		}
	}

	for ( i = 0; i < test_sz; i++ )
	{
		bool b_c = Module::isCoreModule( mdl_itr[i] );
		if ( ( ( i / 2 ) * 2 == i ) &&
			 ( ! b_c ) )
		{
			b_ok = false;
			break;
		}
		else if ( ( ( i / 2 ) * 2 != i ) &&
				  ( b_c ) )
		{
			b_ok = false;
			break;
		}
	}
	if ( b_ok )	TEST_OK
			else	TEST_FAIL
			qDebug() << " - testing core module functionality..." << Outcm;
	performed++; b_ok = true;

	/* half of them removed here, half removed by destructor */
	for ( i = 0; i < test_sz / 2; i++ )
	{
		if ( ( i / 2 ) * 2 == i )
		{
			Module::remCoreModule( mdl_itr[i] );
		}
	}

	for ( i = 0; i < test_sz; i++ )
	{
		delete mdl_itr[i];
	}


}
/* ========================================================================= */
#endif


/*  CLASS    =============================================================== */
//
//
//
//
/* ------------------------------------------------------------------------- */
/* ========================================================================= */
